优劣分析
Pros
Handle multiple connections concurrently
Clean sharing model
Simple and straightforward
Cons
Additional overhead for process control
Nontrivial to share data between processes(IPC)
基本思想
代码实现
xxxxxxxxxx3512void echo(int connfd);34void sigchld_handler(int sig)5{6 while (waitpid(-1, 0, WNOHANG) > 0)7 ; // reap all zombie children8 return;9}1011int main(int argc, char **argv)12{13 int listenfd, connfd;14 socklen_t clientlen;15 struct sockaddr_storage clientaddr;1617 if (argc != 2) {18 fprintf(stderr, "usage: %s <port>\n", argv[0]);19 exit(0);20 }2122 Signal(SIGCHLD, sigchld_handler);23 listenfd = Open_listenfd(argv[1]);24 while (1) {25 clientlen = sizeof(struct sockaddr_storage);26 connfd = Accept(listenfd, (SA *) &clientaddr, &clientlen);27 if (Fork() == 0) {28 Close(listenfd); /* Child closes its listening socket */29 echo(connfd); /* Child services client */30 Close(connfd); /* Child closes connection with client */31 exit(0); /* Child exits */32 }33 Close(connfd); /* Parent closes connected socket (important!) */34 }35}实现对于
fd数组的维护+select调用
xxxxxxxxxx71int select(int n, fd_set *fdset, NULL, NULL, NULL);2// 返回已准备好的描述符的非零的个数,若出错则为 -1。34FD_ZERO(fd_set *fdset); /* Clear all bits in fdset */5FD_CLR(int fd, fd_set *fdset); /* Clear bit fd in fdset */6FD_SET(int fd, fd_set *fdset); /* Turn on bit fd in fdset */7FD_ISSET(int fd, fd_set *fdset); /* Is bit fd in fdset on? */nfds:等待的最大文件描述符 +1
readfds:不为 NULL 时检测集合内可读文件
writefds:不为 NULL 时检测集合内可写文件
exceptfds:不为 NULL 时检测集合内异常文件timeout:若不为 NULL,用来设置阻塞的最大时间返回值大于 0 表示规定时间内有文件被检测,等于 0 表示超时,小于 0 表示发生错误
xxxxxxxxxx4112void echo(int connfd);3void command(void);45int main(int argc, char **argv)6{7 int listenfd, connfd;8 socklen_t clientlen;9 struct sockaddr_storage clientaddr;10 fd_set read_set, ready_set;11 12 if (argc != 2) {13 fprintf(stderr, "usage: %s <port>\n", argv[0]);14 exit(0);15 }16 listenfd = Open_listenfd(argv[1]);17 18 FD_ZERO(&read_set); /* Clear read set */19 FD_SET(STDIN_FILENO, &read_set); /* Add stdin to read set */20 FD_SET(listenfd, &read_set); /* Add listenfd to read set */2122 while (1) {23 ready_set = read_set;24 Select(listenfd + 1, &ready_set, NULL, NULL, NULL);25 if (FD_ISSET(STDIN_FILENO, &ready_set))26 command(); /* Read command line from stdin */27 if (FD_ISSET(listenfd, &ready_set)) {28 clientlen = sizeof(struct sockaddr_storage);29 connfd = Accept(listenfd, (SA *)&clientaddr, &clientlen);30 echo(connfd); /* Echo client input until EOF */31 Close(connfd);32 }33 }34}3536void command(void) {37 char buf[MAXLINE];38 if (!Fgets(buf, MAXLINE, stdin))39 exit(0); /* EOF */40 printf("%s", buf); /* Process the input command */41}
printf是线程安全函数——进程调度的基本单位是线程,单锁不再会导致死锁
xxxxxxxxxx21typedef void *(func)(void *);2int pthread_create(pthread_t *tid, pthread_attr_t *attr, func *f, void *arg);``参数
xxxxxxxxxx41void pthread_exit(void *thread_return);23pthead_t pthread_self(void); //终止自身进程,主进程会等待所有其他对等线程终止4int pthread_cancel(pthread_t tid); //终止tid线程``参数
xxxxxxxxxx11int pthread_join(pthread_t tid, void **thread_return);``参数
xxxxxxxxxx11int pthread_detach(pthread_t tid);``参数
xxxxxxxxxx21pthread_once_t once_control = PTHREAD_ONCE_INIT;2int pthread_once(pthread_once_t *once_control, void (*init_routine)(void));``参数
xxxxxxxxxx91typedef struct {2 int *buf; /* Buffer array */3 int n; /* Maximum number of slots */4 int front; /* buf[(front+1)%n] is first item */5 int rear; /* buf[rear%n] is last item */6 sem_t mutex; /* Protects accesses to buf */7 sem_t slots; /* Counts available slots */8 sem_t items; /* Counts available items */9} sbuf_t;xxxxxxxxxx411234/* Create an empty, bounded, shared FIFO buffer with n slots */5void sbuf_init(sbuf_t *sp, int n)6{7 sp->buf = Calloc(n, sizeof(int));8 sp->n = n; /* Buffer holds max of n items */9 sp->front = sp->rear = 0; /* Empty buffer iff front == rear */10 Sem_init(&sp->mutex, 0, 1); /* Binary semaphore for locking */11 Sem_init(&sp->slots, 0, n); /* Initially, buf has n empty slots */12 Sem_init(&sp->items, 0, 0); /* Initially, buf has zero data items */13}1415/* Clean up buffer sp */16void sbuf_deinit(sbuf_t *sp)17{18 Free(sp->buf);19}2021/* Insert item onto the rear of shared buffer sp */22void sbuf_insert(sbuf_t *sp, int item)23{24 P(&sp->slots); /* Wait for available slot */25 P(&sp->mutex); /* Lock the buffer */26 sp->buf[(++sp->rear) % (sp->n)] = item; /* Insert the item */27 V(&sp->mutex); /* Unlock the buffer */28 V(&sp->items); /* Announce available item */29}3031/* Remove and return the first item from buffer sp */32int sbuf_remove(sbuf_t *sp)33{34 int item;35 P(&sp->items); /* Wait for available item */36 P(&sp->mutex); /* Lock the buffer */37 item = sp->buf[(++sp->front) % (sp->n)]; /* Remove the item */38 V(&sp->mutex); /* Unlock the buffer */39 V(&sp->slots); /* Announce available slot */40 return item;41}
xxxxxxxxxx351/* Global variables */2int readcnt; /* Initially = 0 */3sem_t mutex, w; /* Both initially = 1 */45void reader(void)6{7 while (1) {8 P(&mutex);9 readcnt++;10 if (readcnt == 1) /* First in */11 P(&w);12 V(&mutex);1314 /* Critical section */15 /* Reading happens */1617 P(&mutex);18 readcnt--;19 if (readcnt == 0) /* Last out */20 V(&w);21 V(&mutex);22 }23}2425void writer(void)26{27 while (1) {28 P(&w);29 30 /* Critical section */31 /* Writing happens */3233 V(&w);34 }35}
强扩展,弱扩展
加速比:绝对加速比(T1顺序)+相对加速比(T1并行)
效率
不保护共享变量的的函数
保持跨越多个调用的状态的函数
返回指向静态变量的指针的函数
调用线程不安全函数的函数
显示可重入的:传值传递,所有数据引用都是本地自动栈变量
饮食可重入的:允许传递指针
当一个程序的正确性依赖于一个线程要在另一个线程到达y点之前到达它的控制流中的x点时,就会发生竞争
例如:每个线程都先对S加锁,再对T加锁